#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <signal.h>
#include "struct.h"

#define MAXSIZE 128

#include <ctype.h>

enum {
	HANDINIT = 91,
	HANDACK,
	GETSVRDATA,
	GETINITDATA,
	CLOSECONNECT
};

extern void ulog( const char *fmt, ... );
extern char* execfun( char opt );
extern char* getip();
extern int lic_check(LICENSE *lic);
int expirate();
int ipcheck();

static void sig_term ( int signo );
int optjudge( int fd );

LICENSE lic;
char instance[32];

int main( int argc, char **argv )
{
	int sockfd = 0, ssfd = 0;
	int one  = 1;
	pid_t	pid = 0;
	struct sockaddr_in	sin;
	socklen_t	slen = sizeof(struct sockaddr_in);
	int RPORT = 7897;

	if ( argc != 2 ){
		fprintf( stderr, "Usage: %s port\n", argv[0] );
		exit(0);
	}

	if( lic_check(&lic) < 1 ) {
		fprintf( stderr, "Error: %s start failed for invalid license!\n", argv[0] );
		exit(0);
	}
	if( expirate() < 1 ) {
		fprintf( stderr, "Error: %s start failed. for license has expirated!\n", argv[0] );
		exit(0);
	}
	if( ipcheck() < 1 ) {
		fprintf( stderr, "Error: %s start failed. for invalid IP used!\n", argv[0] );
		exit(0);
	}

	strcpy( instance, argv[0] );
	RPORT = atoi(argv[1]);

	if( (pid = fork()) < 0 ) return -1;
	else if ( pid > 0 ) {
		if ( waitpid(pid, NULL, 0) != pid )
			return -1;
		exit(1);

	}
	/* in child */
	if ( (pid = fork()) < 0 ) return -1;
	else if ( pid > 0 ) sleep(1), exit(0);

	memset( &sin, 0, sizeof(sin) );
	sin.sin_family = AF_INET;	

	if( strcmp(lic.ip , "ANY") == 0 )
		sin.sin_addr.s_addr = htonl( INADDR_ANY );
	else
		sin.sin_addr.s_addr = inet_addr(lic.ip);

	sin.sin_port = htons( RPORT );
#ifdef _IS_LINUX
	sockfd = socket( PF_INET, SOCK_STREAM, 0 );
#elif  _IS_AIX5
	sockfd = socket( AF_INET, SOCK_STREAM, 0 );
#endif
	if ( sockfd < 0 ) {
		fprintf(stderr, "socket:errno=[%d,%s]\n", errno,strerror(errno) );
		ulog( "socket:errno=[%d,%s]\n", errno,strerror(errno) );
		return -1;
	}
	/*SOCK_REUSE  */
	setsockopt( sockfd, SOL_SOCKET ,SO_REUSEADDR,(const char*)&one,sizeof(one) );

	if ( bind(sockfd,(struct sockaddr*)&sin, sizeof(sin)) < 0 ) {
		fprintf( stderr, "bind:failed bind on [%s], errno=[%d,%s]\n", lic.ip, errno,strerror(errno) );
		ulog( "bind:failed bind on [%s] errno=[%d,%s]\n", lic.ip, errno,strerror(errno) );
		return -1;
	}

	fprintf( stderr, "%s [%d] start succeed!\n", argv[0], getpid() );
	signal( SIGTERM, sig_term );

	if ( listen(sockfd, 5) < 0  ) {
		fprintf(stderr, "listen:errno=[%d,%s]\n", errno,strerror(errno) );
		ulog( "listen:errno=[%d,%s]\n", errno,strerror(errno) );
		return -1;
	}
	ulog( "[%s], start succeed!\n", argv[0] );
	while ( 1 ) {
		ssfd = accept( sockfd, (struct sockaddr*)&sin, &slen );
		if ( ssfd < 0 ) {
			ulog( "accept: errno=[%d,%s]\n", sockfd, errno,strerror(errno) );
			exit (-1);
		}
    	if( expirate() < 1 ) {
       		ulog( "Error: %s failed for license has expirated!\n", argv[0] );
       		exit(0);
    	}
		signal( SIGCHLD, SIG_IGN );

		if( optjudge(ssfd) != 1 ) continue;

		switch( fork() ) {
		case 0:
			close( sockfd );
			handler(ssfd);
			close( ssfd );
			exit(0);
		case -1:
			exit(1);
		default:
			close(ssfd);
			break;
		}

	}
}
static void sig_term ( int signo )
{
	if ( signo == SIGTERM ) {
		ulog( "[%s] stoped!\n", instance );
		exit(0);
	} else {
		signal( SIGTERM, sig_term );
	}

}
int optjudge( int fd )
{
	char opt;
	int n = 0;

	memset( &opt, 0, sizeof(opt) );
	n = read( fd, &opt, 1 );
	if ( n < 0 ) {
		ulog( "OPTJUDGE:read errno=[%d,%s]\n", errno,strerror(errno) );
		return -1;
	}
	if( opt == HANDINIT ){  /* a HandShake */
		opt = HANDACK;
		n = write( fd, &opt, sizeof(opt) );
#ifdef DEBUG
		ulog( "OPTJUDGE: HANDINIT\n" );
#endif
		return 1;
	} else
		return -1;
}

int handler(int fd)
{
	int n = 0;
   	char length[8]; char opt[2];
	char rcvmsg[1024], *sndmsg = NULL;
	 
	memset( &opt, 0, sizeof(opt) );
	while( 1 ) {
		n = read( fd, &opt, sizeof(opt) );
		if ( n < 0 ) {
			ulog( "read:errno=[%d,%s]\n", errno,strerror(errno) );
			return -1;
		}
		switch( opt[0] ) {
			case GETSVRDATA: case GETINITDATA: /* Get Server Monitor Data */
				sndmsg = execfun( opt[0] );
				sprintf( length, "%9d", strlen(sndmsg) );
				n = write( fd, length, strlen(length)  );
#ifdef DEBUG
				ulog( "DEBUG:handler lengh=[%s] sndmsg=[%s]\n", length, sndmsg);
#endif
				n = write( fd, sndmsg, strlen(sndmsg) );
				if ( n < 0 ) {
					ulog( "write:errno=[%d,%s]\n", errno,strerror(errno) );
					return -1;
				}
				if( sndmsg ) free( sndmsg ), sndmsg = NULL;
				break;

			case CLOSECONNECT: /* Close this Connection */
#ifdef DEBUG
				ulog( "DEBUG:CLOSECONNECT\n");
#endif
				return 0;

				break;
			default:
				break;
		}
	}
}

int expirate()
{
	struct tm *now = NULL;
	int m_year = 0, m_month= 0, m_day = 0;

	time_t curtime = time(NULL);

    now = localtime(&curtime);
	if( strcmp(lic.expiration , "NONE") == 0 ) 
		return 1;
	sscanf( lic.expiration, "%4d-%2d-%2d", &m_year, &m_month, &m_day );

	now->tm_year+=1900; now->tm_mon +=1;

	if( m_year < now->tm_year ) return -1;
	if( m_year == now->tm_year && m_month < now->tm_mon ) return -1;
	if( m_year == now->tm_year && m_month == now->tm_mon && m_day < now->tm_mday ) return -1;

	return 1;
	
}
int ipcheck()
{
	if( strcmp(lic.ip , "ANY") == 0 ) 
		return 1;
	if( strcmp( lic.ip, getip() ) == 0 ) 
		return 1;

	return 1;
}
